/*************************************************************************
	> File Name: ./src/CentralCache.cpp
	> Author: zq
	> Mail: zhouquan1511@163.com 
	> Created Time: Thu 27 Apr 2023 07:25:52 PM CST
 ************************************************************************/
#include "CentralCache.h"
#include "PageCache.h"

CentralCache CentralCache::_sInst;

//在对应哈希桶中获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList &spanList, size_t size) {
	//1 遍历spanlist，查找非空span
	Span *it = spanList.Begin();
	while (it != spanList.End()) {
		if (it->_freeList  != nullptr) {
			return it;
		}
		else {
			it=it->_next;
		}
	}

	spanList->_mtx.unlock();
	PageCache::GetInstance()->_pageMtx.lock();
	//2 size对应的spanlist无span，向pageCache申请大页span
	Span *span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
	span->_objSize = size;
	span->_isUse = true;
	PageCache::GetInstance()->_pageMtx.unlock();

	//2 size对应的spanlist无span，向pageCache申请大页span
	//3 将pageCache返回的span进行内存切分，构造自由链表并插入到centralCache对应的桶位置上
	char *start = (char*)(span->_pageId << PAGE_SHIFT);
	size_t bytes = span->_n << PAGE_SHIFT;
	char *end = start + bytes;

	//采用尾插法构造自由链表_freeList，提高CPU缓存利用率cpu cache line
	span->_freeList = start;
	start += size;
	void *tail = span->_freeList;
	while (start < end) {
		NextObj(tail) = start;
		tail = start;
		start += size;
	}
	NextObj(tail) = nullptr;
	spanlist->_mtx.lock();

	spanList.PushFront(span);
	return span;
}

//从central cache获取一定数量的对象给thread cache
size_t CentralCache::FetchRangeObj(void *&start, void *&end,
								size_t n, size_t size) {
	size_t index = SizeClass::Index(size);
	_spanLists[index]._mtx.lock();
	
	//在对应哈希桶上获取一个span
	Span *span = GetOneSpan(_spanLists[index], size);
	assert(span);
	assert(span->_freeList);

	//从span中获取n个对象,如果不够有多少拿多少
	start = span->_freeList;
	end = span->_freeList;
	size_t actualNum = 1;
	while (NextObj(end)&&n - 1) {
		end = NextObj(end);
		n --;
		actualNum ++;
	}
	span->_freeList = NextObj(end);
	NextObj(end) = nullptr;
	span->_useCount += actualNum;

	_spanLists[index]._mtx.unlock();
	return actualNum;
}

void CentralCache::ReleaseListToSpans(void *start, size_t size) {
	size_t index = SizeClass::Index(size);
	_spanLists[index]._mtx.lock();
	
	while (start) {
		void *next = NextObj(start);
		Span *span = PageCache::GetInstance()->MapObjectToSpan(start);
		NextObj(start) = span->_freeList;
		span->_freeList = start;
		
		//此时该Span分配出去的对象全部收回，将其归还给下层pageCache
		if (--span->_useCount == 0) {
			//在centralCache层删除该Span
			_spanLists[index].Erase(span);
			span->_freeList = nullptr;
			span->_prev = nullptr;
			span->_next = nullptr;

			//归还Span
			_spanLists[index]._mtx.unlock();
			PageCache::GetInstance()->_pageMtx.lock();
			PageCache::GetInstance()->ReleaseSpanToPageCache(span);
			PageCache::GetInstance()->_pageMtx.unlock();
			_spanLists[index]._mtx.lock();
		}
		start = next;
	}
	_spanLists[index]._mtx.unlock();
}

